package org.microservice.gateway.service.impl;

import com.alibaba.fastjson.JSON;
import com.netflix.zuul.context.RequestContext;
import com.xiaoleilu.hutool.io.IoUtil;
import com.xiaoleilu.hutool.util.URLUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.microservice.common.entity.SysLog;
import org.microservice.common.util.CustomRuntimeException;
import org.microservice.common.util.IPUtils;
import org.microservice.common.util.constant.MqQueueConstant;
import org.microservice.gateway.service.LogSendService;
import org.microservice.redis.util.RedisService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

/**
 * @author lengleng
 * @date 2017/11/16
 * 消息发往消息队列工具类
 */
@Component
@Slf4j
public class LogSendServiceImpl implements LogSendService {
    private static final String SERVICE_ID = "serviceId";
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedisService redisService;

    /**
     * 1. 获取 requestContext 中的请求信息
     * 2. 如果返回状态不是OK，则获取返回信息中的错误信息
     * 3. 发送到MQ
     *
     * @param requestContext 上下文对象
     */
    @Override
    public void send(RequestContext requestContext) {




        HttpServletRequest request = requestContext.getRequest();


        SysLog sysLog = new SysLog();


        String path = URLUtil.getPath(request.getRequestURI());

        if(path.matches("^.*/oauth/token.*$")){
            Map<String, String[]> parameterMap = request.getParameterMap();
            String username = parameterMap.get("username")[0];
            sysLog.setUserName(username);

        }else{

            String token="";
            String authorization = request.getHeader("Authorization");
            if(StringUtils.isNotBlank(authorization)){
                String[] split = authorization.split(" ");
                token = split[1];
            }else{
                Map<String, String[]> parameterMap = request.getParameterMap();
                String[] access_tokens = parameterMap.get("access_token");
                if(access_tokens != null && access_tokens.length> 0){
                    token = parameterMap.get("access_token")[0];
                }

            }

            if(StringUtils.isNotBlank(token)){
                if(redisService.exists(token)){
                    String username = redisService.get(token).toString();
                    sysLog.setUserName(username);
                }

            }


        }

        HttpServletResponse response = requestContext.getResponse();
        long startTime = (long)requestContext.get("startTime");
        sysLog.setExecuteTime(System.currentTimeMillis() - startTime);
        sysLog.setMethod(request.getMethod());
        sysLog.setRemoteAddr(IPUtils.getIpAddr(request));
        sysLog.setRequestUri(path);
        sysLog.setServiceId((String) requestContext.get("serviceId"));
        //网关内部异常
        Throwable throwable = requestContext.getThrowable();
        if (throwable != null) {
            log.error("网关异常", throwable);
            sysLog.setException("网关异常："+throwable.getCause().toString());

        }else{
            if (requestContext.getResponseStatusCode() != HttpStatus.SC_OK
                    && requestContext.getResponseDataStream() != null) {

                InputStream inputStream = requestContext.getResponseDataStream();

                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                InputStream stream1 = null;
                byte[] buffer = IoUtil.readBytes(inputStream);
                String s = new String(buffer, 0, buffer.length);
                sysLog.setException(s);

                try {
                    baos.write(buffer);
                    baos.flush();
                    stream1 = new ByteArrayInputStream(baos.toByteArray());
                    requestContext.setResponseDataStream(stream1);
                } catch (IOException e) {
                    log.error("响应流解析异常：", e);
                    throw new CustomRuntimeException("网关响应流异常");
                } finally {
                    IoUtil.close(stream1);
                    IoUtil.close(baos);
                    IoUtil.close(inputStream);
                }

            }
        }



        sysLog.setResponseStatus(response.getStatus());
        sysLog.setUserAgent(request.getHeader("user-agent"));

        rabbitTemplate.convertAndSend(MqQueueConstant.LOG_QUEUE, JSON.toJSONString(sysLog));


    }
}
